package me.zhengjie.modules.system.service.impl

import me.zhengjie.common.utils.*
import me.zhengjie.common.utils.FileUtil.downloadExcel
import me.zhengjie.modules.system.domain.Area
import me.zhengjie.modules.system.repository.AreaRepository
import me.zhengjie.modules.system.service.AreaService
import me.zhengjie.modules.system.service.dto.*
import me.zhengjie.modules.system.service.mapper.AreaMapper
import jakarta.persistence.criteria.CriteriaBuilder
import jakarta.persistence.criteria.CriteriaQuery
import jakarta.persistence.criteria.Root
import jakarta.servlet.http.HttpServletResponse
import org.springframework.cache.annotation.CacheConfig
import org.springframework.cache.annotation.CacheEvict
import org.springframework.cache.annotation.Cacheable
import org.springframework.data.domain.Pageable
import org.springframework.data.jpa.domain.Specification
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Propagation
import org.springframework.transaction.annotation.Transactional
import java.io.IOException
import java.util.function.Supplier

/**
 * @author kuki
 * @date 2022-07-21
 */
@Service
@CacheConfig(cacheNames = ["area"])
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = [Exception::class])
class AreaServiceImpl(private val areaRepository: AreaRepository, private val areaMapper: AreaMapper) : AreaService {
    @Cacheable(key = "'queryall_criteria_pageable'")
    override fun queryAll(criteria: AreaQueryCriteria, pageable: Pageable?): Any? {
        val page =
            areaRepository.findAll(Specification { root: Root<Area?>, criteriaQuery: CriteriaQuery<*>?, criteriaBuilder: CriteriaBuilder ->
                QueryHelp.getPredicate(
                    root,
                    criteria,
                    criteriaBuilder
                )
            }, pageable!!)
        return PageUtil.toPage(page.map { entity: Area? -> areaMapper.toDto(entity) })
    }

    @Cacheable(key = "'queryall_criteria'")
    override fun queryAll(criteria: AreaQueryCriteria?): List<AreaDTO?>? {
        return areaMapper.toDto(areaRepository.findAll { root: Root<Area?>, criteriaQuery: CriteriaQuery<*>?, criteriaBuilder: CriteriaBuilder ->
            QueryHelp.getPredicate(
                root,
                criteria,
                criteriaBuilder
            )
        })
    }

    @Cacheable(key = "'findbyid'+#p0")
    override fun findById(id: Int): AreaDTO? {
        val area = areaRepository.findById(id).orElseGet(Supplier<Area> { Area() })
        ValidationUtil.isNull(area!!.id, "Area", "id", id)
        return areaMapper.toDto(area)
    }

    @CacheEvict(allEntries = true)
    @Transactional(rollbackFor = [Exception::class])
    override fun create(resources: Area): AreaDTO? {
        return areaMapper.toDto(areaRepository.save(resources))
    }

    @CacheEvict(allEntries = true)
    @Transactional(rollbackFor = [Exception::class])
    override fun update(resources: Area) {
        val area = areaRepository.findById(resources.id!!).orElseGet(Supplier<Area> { Area() })
        ValidationUtil.isNull(area!!.id, "Area", "id", resources.id!!)
        area.copy(resources!!)
        areaRepository.save(area)
    }

    @CacheEvict(allEntries = true)
    @Transactional(rollbackFor = [Exception::class])
    override fun delete(id: Int) {
        areaRepository.deleteById(id)
    }

    @Throws(IOException::class)
    override fun download(all: List<AreaDTO?>?, response: HttpServletResponse?) {
        val list: MutableList<Map<String?, Any?>?> = ArrayList()
        if (all != null) {
            for (area in all) {
                val map: MutableMap<String?, Any?> = LinkedHashMap()
                map["区域名称"] = area!!.name
                map["城市代码"] = area!!.cityCode
                list.add(map)
            }
        }
        downloadExcel(list, response!!)
    }
}